#include "stdafx.h"

#include "resource.h"


#include "waconsts.h"
#include "waitbox.h"
#include "datastore.h"
#include "config.h"
#include "utilities.h"
#include "fftcalculator.h"

#include "FFTGraphView.h"



#pragma warning( disable : 4244)

const double componentDef[10]={0.3,0.3,4.0,4.0,8.0,8.0,14.0,14.0,30.0,30.0};



void CFFTGraphView::DrawThumbnail(int eid,Bitmap *bmp,int w,int h)
{
	if(!calc)
		throw EEG_Exceptions(11,_T("FFTG: Invalid Calculator"));
	Graphics* graph = Graphics::FromImage(bmp);
	//graph->Clear(Color(BG_COLOR));

	int index=calc->EID2Index(eid);
	if(index==-1){
		Pen pen(Color(255,255,255),2.0);
		graph->FillRectangle(new SolidBrush(Color(128,128,128)),0,0,w,h);
		graph->DrawString(_T("No FFT Output"),-1,new Font(TEXT_FONT,12),PointF(0.0,0.0),
			new SolidBrush(Color(255,0,0)));
		SAFE_DELETE(graph);
		return ;
	}
	const std::vector<FFTOutput> &out = calc->GetOutputs();
	const int SR = calc->GetSource()->GetSamplingRate();
	double max=out[0].max;
	
	for(size_t i=0;i<out.size();i++)
		max=(max<out[i].max)?out[i].max:max;
	const unsigned int N=(out[index].e-out[index].b);
	const unsigned int count=(FFT_MAX_FREQ< SR/2)?(N*FFT_MAX_FREQ/SR+1):
			SR/2;
	const double wScaler=1.0/count*w;
	const double hScaler=1.0/max*h*0.95;

	//FontFamily   fontFamily(TEXT_FONT);
	//-------------------draw graph-----------------------------------------------	
	for(unsigned int i=1;i<count;i+=1){
		double x=i*wScaler;
		double y=h-out[index].abs[i]*hScaler;
		double r,g,b;
		HSLtoRGB(240*out[index].abs[i]/out[index].max,240,120,&r,&g,&b);
		SolidBrush sb(Color(r,g,b));
		graph->FillRectangle(&sb,RectF(x,y,ceil(wScaler),out[index].abs[i]*hScaler));
	}
	SAFE_DELETE(graph);
}

void CFFTGraphView::DrawBitmap(int eid,Bitmap &bmp,int w,int h)
{
	if(!calc)
		throw EEG_Exceptions(11,_T("FFTG: Invalid Calculator"));
	unsigned int index = calc->EID2Index(eid);

	//bmp=new Bitmap(w,h);
	Graphics* graph = Graphics::FromImage(&bmp);
	graph->Clear(COLORREF2Color(Config::SPE_BGColor));
	
	if(index ==-1)
	{
		Pen pen(Color(255,255,255),2.0);
		graph->DrawLine(&pen,0,0,w,h);
		graph->DrawLine(&pen,0,h,w,0);
		graph->DrawString(L"No FFT Output",-1,new Font(TEXT_FONT,24),PointF(0.0,0.0),new SolidBrush(Color(255,0,0)));
		return ;
	}else
	{
		TCHAR buf[256];

		//const unsigned int count=(out[ch].e-out[ch].b)/2+1;
		const std::vector<FFTOutput> &out = calc->GetOutputs();
		const unsigned int N=(out[index].e-out[index].b);
		const int SR = calc->GetSource()->GetSamplingRate();
		const unsigned int count=(FFT_MAX_FREQ<SR/2)?(N*FFT_MAX_FREQ/SR+1):
			SR/2;
		const int graphWidth=w-2*MARGIN_WIDTH;
		const int graphHeight=h-2*MARGIN_WIDTH;
		const double wScaler=1.0/count*graphWidth;
		const double hScaler=1.0/out[index].max*graphHeight*MAX_SCALER;

		FontFamily   fontFamily(TEXT_FONT);
		//-------------------draw graph-----------------------------------------------	
		for(unsigned int i=1;i<count;i++){
			double x=MARGIN_WIDTH+i*wScaler;
			double y=MARGIN_WIDTH+graphHeight-out[index].abs[i]*hScaler;

			bool isWhite=1;
			double r,g,b;
			double f=double(i)*FFT_MAX_FREQ/count;
			if(f>=0 && f<componentDef[0]) r=51,g=198,b=99,isWhite=0;
			if(f>=componentDef[1] && f<componentDef[2]) r=27,g=100,b=22,isWhite=0;
			if(f>=componentDef[3] && f<componentDef[4]) r=150,g=232,b=150,isWhite=0;
			if(f>=componentDef[5] && f<componentDef[6]) r=226,g=119,b=22,isWhite=0;
			if(f>=componentDef[7] && f<componentDef[8]) r=150,g=20,b=200,isWhite=0;
			if(f>=componentDef[9]) r=255,g=248,b=96,isWhite=0;
			if(isWhite) r=255,g=255,b=255;

			SolidBrush sb(Color(r,g,b));

			graph->FillRectangle(&sb,RectF(x,y,ceil(wScaler),out[index].abs[i]*hScaler));
		}
		//----------------------------------------------------------------------------------------

		graph->DrawRectangle(new Pen(Color(255,255,255),AXIS_WIDTH),
			RectF(MARGIN_WIDTH,MARGIN_WIDTH,graphWidth,graphHeight));//draw axis

		const double freq_seg=FFT_MAX_FREQ/AXIS_SEGMENT;
		Font         font1(&fontFamily, AXIS_TEXT_SIZE, FontStyleBold, UnitPoint);
		SolidBrush   sb1(Color(255,255,255));

		for(int i=0;i<AXIS_SEGMENT;i++){//x axis
			int x=MARGIN_WIDTH+graphWidth/AXIS_SEGMENT*i;
			int y=MARGIN_WIDTH+graphHeight;
			graph->DrawLine(new Pen(Color(255,255,255)),x,y,x,y-15);
			//_itow((int)(freq_seg*i),buf,10);
			swprintf(buf,256,L"%4.2f",freq_seg*i);
			graph->DrawString(buf,-1,&font1,PointF(x-AXIS_TEXT_SIZE,y+5.0),&sb1);
		}

		const double cur_seg=out[index].max*2/N/MAX_SCALER/AXIS_SEGMENT;
		for(int i=AXIS_SEGMENT;i>0;i--){//y axis
			int x=MARGIN_WIDTH;
			int y=MARGIN_WIDTH+graphHeight/AXIS_SEGMENT*i;
			graph->DrawLine(new Pen(Color(255,255,255)),x,y,x+15,y);
			swprintf(buf,256,L"%4.2f",cur_seg*(AXIS_SEGMENT-i));
			graph->DrawString(buf,-1,&font1,PointF(x-MARGIN_WIDTH+5.0,y-AXIS_TEXT_SIZE),&sb1);
		}
		//CLSID   encoderClsid;
		//GetEncoderClsid(L"image/bmp", &encoderClsid);
		//bmp->Save(L"Lddd.bmp",&encoderClsid);

		swprintf(buf,256,L"FFT Graph @ Ch. %d(\"%s\" eid=%d)\nref: %s  res=%.2g[Hz]",index,
			calc->GetSource()->GetChannelByEID(eid)->electrode.name , calc->GetSource()->GetChannelByEID(eid)->electrodeID
			, calc->GetSource()->GetRefTypeString(), output_resolution(SR,(N-1)*2));
		Font         font(&fontFamily, TITLE_SIZE, FontStyleBold, UnitPoint);
		RectF        rTitle(0.0f, 0.0f, w, MARGIN_WIDTH);
		StringFormat stringFormat;
		SolidBrush   sb2(Color( 255, 255, 0));
		stringFormat.SetAlignment(StringAlignmentCenter);
		graph->DrawString(buf, -1, &font, rTitle, &stringFormat, &sb2);//draw title

		SolidBrush   sb3(Color( 0, 255, 255));
		Font         font2(&fontFamily, AXIS_TEXT_SIZE, FontStyleBold, UnitPoint);
		graph->DrawString(L"Cur.[uA]",-1,&font2,PointF(5.0,MARGIN_WIDTH-5.0-TEXT_SIZE),&sb3);
		graph->DrawString(L"Freq.[Hz]",-1,&font2,PointF(MARGIN_WIDTH+graphWidth-TEXT_SIZE ,MARGIN_WIDTH+5.0+graphHeight),&sb3);

		Font         font3(&fontFamily, DATE_TEXT_SIZE, FontStyleBold, UnitPoint);
		stringFormat.SetAlignment(StringAlignmentFar);
		graph->DrawString(getTimeString(),-1,&font3,RectF(0.0,h-2*DATE_TEXT_SIZE,w,2*DATE_TEXT_SIZE),&stringFormat,new SolidBrush(Color(200,200,200)));


	}
	SAFE_DELETE(graph);
}

int CFFTGraphView::selectChannel(int x, int y)
{
	RECT r;
	int ret=-1;
	this->GetClientRect(&r);

	const double gw=r.right-2.0*MARGIN_WIDTH;
	const double gh=(r.bottom-2.0*MARGIN_WIDTH)/FFT_GRAPH_PER_PAGE;

	for(int i=0;i<FFT_GRAPH_PER_PAGE;i++){
		if(x>MARGIN_WIDTH && x<(MARGIN_WIDTH+gw) && (y>MARGIN_WIDTH+gh*i) && (y<MARGIN_WIDTH+gh*(i+1)))
		{
			ret=currentPage*FFT_GRAPH_PER_PAGE+i;
			break;
		}
	}
	if(ret>= calc->GetOutputCount() || (ret==-1))
		ret=-1;

	if(ret!=-1)
		selectedChannelEID=calc->Index2EID(ret);
	return selectedChannelEID;
}


void CFFTGraphView::DrawAllOutput(Bitmap &bmp,int w,int h ,bool isdrawbox)
{
	TCHAR buf[256], buf1[256];
	FontFamily   fontFamily(TEXT_FONT);
	StringFormat stringFormat;
	Font         font1(&fontFamily, AXIS_TEXT_SIZE, FontStyleBold, UnitPoint);
	Font         font3(&fontFamily, DATE_TEXT_SIZE, FontStyleBold, UnitPoint);
	Graphics* graph = Graphics::FromImage(&bmp);
//graph->Clear(BG_COLOR);
	const double gw=w-2.0*MARGIN_WIDTH;
	const double gh=(h-2.0*MARGIN_WIDTH)/FFT_GRAPH_PER_PAGE;

	for(int i=0;i<FFT_GRAPH_PER_PAGE;i++){
		int index = currentPage*FFT_GRAPH_PER_PAGE+i;
		int eid = calc->Index2EID(index);
		int indexofBuf = EID2IndexofBuf(eid);
		CWaitBoxDlg wbd;
		wbd.SetPrompt(_T("Drawing"));
		if(indexofBuf == -1){
			BMPBuffer tmp;
			tmp.eid=eid;
			tmp.bmp=new Bitmap(gw,gh);
			DrawThumbnail(eid ,tmp.bmp,gw,gh);
			bmpBuf.push_back(tmp);
			indexofBuf=bmpBuf.size()-1;
		}
		graph->DrawImage(bmpBuf[indexofBuf].bmp,
			RectF(MARGIN_WIDTH,MARGIN_WIDTH+gh*i,gw,gh));
		if(eid==-1){
			swprintf(buf,256,L"None");
		}else{
			swprintf(buf,256,L"%s\neid=%d",calc->GetSource()->GetChannelByEID(eid)->electrode.name,eid);
			const FFTOutput &tmpo = calc->GetOutputs()[calc->EID2Index(eid)];
			UINT N = tmpo.e-tmpo.b;
			swprintf(buf1,256 ,_T("%.4g[uVP]\n%.4g[Hz]"),tmpo.max*2/N,(double)output_fftpoint2freq(tmpo.max_index,calc->GetSource()->GetSamplingRate() ,N));
			graph->DrawString(buf1,-1, &font3, PointF(MARGIN_WIDTH +gw +2.0,MARGIN_WIDTH+gh*i ),new SolidBrush(Color(255,255,120)));
		}
	
		graph->DrawString(buf,-1,&font1,PointF(5.0,MARGIN_WIDTH+gh*i+5.0),new SolidBrush(Color(255,255,255)));

	}

	for(int i=0;i<FFT_GRAPH_PER_PAGE;i++){
		graph->DrawRectangle(new Pen(Color(255,255,255),AXIS_WIDTH),
			RectF(MARGIN_WIDTH,MARGIN_WIDTH+gh*i,gw,gh));
	}



	SolidBrush   sb2(Color( 255, 255, 0));
	stringFormat.SetAlignment(StringAlignmentCenter);

	stringFormat.SetAlignment(StringAlignmentFar);
	graph->DrawString(getTimeString(),-1,&font3,
		RectF(0.0,h-2*DATE_TEXT_SIZE,w,2*DATE_TEXT_SIZE),&stringFormat,new SolidBrush(Color(200,200,200)));
	swprintf(buf,256,L"FFT Graph (%d)\nref: %s" ,currentPage+1, calc->GetSource()->GetRefTypeString());
	Font         font(&fontFamily, TITLE_SIZE, FontStyleBold, UnitPoint);
	RectF        rTitle(0.0f, 0.0f, w, MARGIN_WIDTH);
	stringFormat.SetAlignment(StringAlignmentCenter);
	graph->DrawString(buf, -1, &font, rTitle, &stringFormat, &sb2);//draw title

	graph->DrawString(_T("Peak"),-1, &font1, PointF(MARGIN_WIDTH + gw+ 10.0, MARGIN_WIDTH -30.0),new SolidBrush(Color(255,255,255)));

	if(selectedChannelEID!=-1 && isdrawbox){
		graph->DrawRectangle(new Pen(Color(255,255,0),AXIS_WIDTH),
			RectF(MARGIN_WIDTH,MARGIN_WIDTH+gh*(calc->EID2Index(selectedChannelEID)-FFT_GRAPH_PER_PAGE*currentPage),gw,gh));
	}//draw yellow box
	SAFE_DELETE(graph);
}


void CFFTGraphView::OnDraw(HDC hdc){
	RECT rcBounds;
	GetClientRect(&rcBounds);
	rcBounds.bottom-=TOOLBAR_HEIGHT;
	Rect rc(rcBounds.left,rcBounds.top,rcBounds.right,rcBounds.bottom);
	Bitmap bmp(rcBounds.right,rcBounds.bottom);//memory bitmap
	Graphics graphics(hdc); 

	FontFamily  fontFamily(_T("Times New Roman"));
	Font        font(&fontFamily, 24, FontStyleRegular, UnitPixel);
	SolidBrush  solidBrush(Color(255, 255, 255, 255));


	// Create a Graphics object that is associated with the image.
	Graphics* graph = Graphics::FromImage(&bmp);
	if(!calc){
		MessageBox(_T("No input!"));
		DestroyWindow();
		return;
	}
	//graph->Clear(BG_COLOR);
	if(calc->isReady())
	{
		if(viewType==false || selectedChannelEID==-1){
			DrawAllOutput(bmp,rcBounds.right,rcBounds.bottom);
		}else{
			//Bitmap bmp(rcBounds.right,rcBounds.bottom);
			DrawBitmap(selectedChannelEID,bmp,rcBounds.right,rcBounds.bottom);
		}

	}else{
		
		graph->DrawString(_T("Data is NOT available!"),-1,&font,PointF(0.0,0.0),&solidBrush);
	}

	// Draw the altered image.
	graphics.DrawImage(&bmp,rcBounds.left,rcBounds.top+TOOLBAR_HEIGHT,rcBounds.right,rcBounds.bottom);
	SAFE_DELETE(graph);
}

int CFFTGraphView::EID2IndexofBuf(int eid)
{
	int ret=-1;
	for(int i=0;i<bmpBuf.size();i++){
		if(bmpBuf[i].eid == eid){
			ret=i;break;
		}
	}
	return ret;
}

void CFFTGraphView::UpdateBitmapBuffer(void)
{
	for(size_t i=0;i<bmpBuf.size();i++)
		SAFE_DELETE(bmpBuf[i].bmp);
	bmpBuf.clear();
}

void CFFTGraphView::DrawToFile(LPCTSTR filename, int eid,unsigned long w,unsigned long h){
	CLSID   encoderClsid;
	GetEncoderClsid(L"image/bmp", &encoderClsid);
	Bitmap bmp(w,h);
	DrawBitmap(eid,bmp,w,h);
	bmp.Save(filename,&encoderClsid);
}

void CFFTGraphView::DrawAllToFile(LPCTSTR filename ,unsigned long w,unsigned long h){
	CLSID   encoderClsid;
	GetEncoderClsid(L"image/bmp", &encoderClsid);
	Bitmap bmp(w,h);
	DrawAllOutput(bmp,w,h,0);
	bmp.Save(filename,&encoderClsid);
}